Skip to content

Conversation

@nishanth-kj
Copy link
Contributor

@nishanth-kj nishanth-kj commented Oct 26, 2025

Related Issue


Description

Add a centralized AuthContext that stores GitHub username and personal access token (PAT), persists them to localStorage, and exposes getOctokit() and logout(). Add a Profile page to view and edit credentials. Wire authentication into the navbar and routing so the UI reflects authenticated state and provides a profile dropdown and logout.

Changes

  • src/context/AuthContext.tsx — New AuthProvider persisting username and token, exposing getOctokit() and logout().
  • src/pages/Profile/Profile.tsx — New profile page to view/edit GitHub username and PAT. Saves to AuthContext and navigates back on save.
  • src/Routes/Router.tsx — Added /profile route.
  • src/components/Navbar.tsx — Show username when authenticated. Dropdown with View/Edit Profile and Logout. Mobile menu reflects auth state.
  • src/main.tsx — App wrapped in AuthProvider.
  • src/pages/Tracker/Tracker.tsx — Switched to using AuthContext for username/token and getOctokit().

Rationale

Centralizes auth state to avoid duplicated token/username management and enable consistent UX (profile dropdown, logout, profile editing). localStorage provides simple persistence for now. Consider more secure storage for production.

How Has This Been Tested?

  • Local development run.
  • Production build: vite build succeeded.
  • Manual test flows:
    • Save username + PAT on Profile page.
    • Navbar updates to show username and dropdown.
    • Logout clears stored credentials and updates UI.
    • Tracker page uses AuthContext for API calls.

Notes / Next Steps

  • Add user avatar fetch for navbar.
  • Add logout confirmation modal.
  • Replace localStorage with secure storage for PATs in production.

Screenshots

(If needed, add screenshots showing Profile page and updated Navbar.)

Type of Change

  • New feature
  • Bug fix
  • Code style update
  • Breaking change
  • Documentation update

Release Notes

  • Added Profile page for managing GitHub credentials.
  • Added global AuthContext with getOctokit() and logout().
  • Navbar shows authenticated user, profile actions, and logout.
  • Tracker now uses centralized auth.

… logout

Add app-wide AuthContext and Profile page, wire into navbar and routing

Changes:
- src/context/AuthContext.tsx: new Auth provider that stores GitHub username and personal access token, persists to localStorage, exposes getOctokit() and logout().
- src/pages/Profile/Profile.tsx: new page to view/edit GitHub username and token. Saves to AuthContext and navigates back on save.
- src/Routes/Router.tsx: added /profile route.
- src/components/Navbar.tsx: updated header to show username when authenticated, with a dropdown containing View/Edit Profile and Logout. Mobile menu updated similarly.
- src/main.tsx: app wrapped with AuthProvider so auth is available globally.
- src/pages/Tracker/Tracker.tsx: switched to using AuthContext for username/token and getOctokit instead of local hook, so auth is centralized.

Rationale:
Centralized auth state enables consistent UX (navbar profile dropdown, logout, and profile editing) and avoids duplicating token/username state across pages. Storing credentials in localStorage provides a simple persistence layer; consider a more secure approach for production.

Testing/Validation:
- Ran a production build (vite build) locally; build succeeded.

Notes and next steps:
- Consider adding avatar fetch for the navbar, logout confirmation, and secure storage for PATs.
@netlify
Copy link

netlify bot commented Oct 26, 2025

Deploy Preview for github-spy ready!

Name Link
🔨 Latest commit 7ccb6ee
🔍 Latest deploy log https://app.netlify.com/projects/github-spy/deploys/68fe31fd0335b8000915d99e
😎 Deploy Preview https://deploy-preview-214--github-spy.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 26, 2025

Walkthrough

The pull request introduces user authentication and profile management by creating an AuthContext, adding a Profile page route, and refactoring authentication state management across the application. Navbar now displays a user dropdown for authenticated users, Tracker consumes AuthContext instead of a hook, and all child components are wrapped with AuthProvider.

Changes

Cohort / File(s) Summary
Authentication Infrastructure
src/context/AuthContext.tsx, src/main.tsx
New AuthContext with username, token, and Octokit client management. Includes localStorage persistence and logout functionality. AuthProvider wraps the application in main.tsx to provide context scope.
Navigation & Routing
src/Routes/Router.tsx, src/components/Navbar.tsx
Added /profile route rendering Profile component. Navbar refactored to integrate AuthContext, displaying authenticated user dropdown with View/Edit Profile and Logout actions, with fallback Login link for unauthenticated users.
New Page
src/pages/Profile/Profile.tsx
New Profile component for editing GitHub username and Personal Access Token, persisting changes via AuthContext setters and navigating back to root on submission.
State Management Migration
src/pages/Tracker/Tracker.tsx
Replaced useGitHubAuth hook with AuthContext via useContext, sourcing username, token, and getOctokit from context with fallback values.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as UI Components
    participant Auth as AuthContext
    participant Storage as localStorage

    User->>UI: Click View/Edit Profile
    UI->>Auth: Access username & token
    Auth->>Storage: Hydrate from localStorage
    Storage-->>Auth: Return stored values
    Auth-->>UI: Provide auth state
    UI->>UI: Show Profile form pre-filled
    
    User->>UI: Update credentials & Submit
    UI->>Auth: Call setUsername & setToken
    Auth->>Storage: Persist new values
    Storage-->>Auth: Confirmed
    Auth-->>UI: State updated
    UI->>UI: Navigate to root
    
    User->>UI: Click Logout
    UI->>Auth: Call logout()
    Auth->>Storage: Clear localStorage
    Storage-->>Auth: Cleared
    Auth-->>UI: State reset
    UI->>UI: Show Login link
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • AuthContext implementation: Verify localStorage hydration logic, error handling in getOctokit, and proper context typing.
  • Navbar authentication logic: Confirm dropdown state management, navigation routes, and logout flow consistency.
  • Tracker migration: Ensure fallback values don't break existing data-fetching behavior and that context consumption is correct.
  • Profile form validation: Check for missing input validation or error handling during credential updates.

Suggested labels

level1

Poem

🐰 A profile page hops into view,
Auth context brings credentials anew,
Login flows, dropdowns, and localStorage keep,
User preferences now stored safe and deep!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title "Add app-wide AuthContext, Profile page, and navbar integration (Closes #47)" accurately captures the three main components added in this changeset: a centralized authentication context for app-wide use, a new Profile page for editing credentials, and integration of authentication features into the Navbar component. The title is specific and descriptive, clearly conveying the primary changes without vague terminology or unnecessary noise. A developer scanning the repository history would understand that this PR introduces authentication infrastructure with corresponding UI components.
Description Check ✅ Passed The pull request description follows the repository template structure and includes all required sections: Related Issue is correctly formatted with "Closes: #47", a comprehensive Description section explains the changes, How Has This Been Tested includes specific test scenarios and build verification, and Type of Change properly identifies this as a New feature with the checkbox marked. The author has also included additional valuable sections like Changes (file-by-file breakdown), Rationale (explaining the centralization approach), and Notes/Next Steps (identifying future improvements), which enhance clarity beyond the template minimum. The description is well-organized, detailed, and demonstrates good understanding of the PR objectives.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@nishanth-kj nishanth-kj marked this pull request as ready for review October 26, 2025 14:37
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/Navbar.tsx (1)

169-198: Fix mobile menu UX inconsistency.

The mobile menu shows the Login link unconditionally (lines 169-175) while also showing Profile/Logout buttons when authenticated (lines 176-198). This creates a confusing experience where authenticated users see both "Login" and "Logout" options. The desktop menu correctly shows either the user dropdown OR the login link.

Apply this diff to conditionally render the Login link:

            <Link
              to="/contributors"
              className="block text-lg font-medium hover:text-gray-300 transition-all px-2 py-1 border border-transparent hover:border-gray-400 rounded"
              onClick={() => setIsOpen(false)}
            >
              Contributors
            </Link>
-           <Link
-             to="/login"
-             className="block text-lg font-medium hover:text-gray-300 transition-all px-2 py-1 border border-transparent hover:border-gray-400 rounded"
-             onClick={() => setIsOpen(false)}
-           >
-             Login
-           </Link>
            {auth && auth.username && (
              <>
                <button
                  onClick={() => {
                    setIsOpen(false);
                    navigate('/profile');
                  }}
                  className="block text-left w-full text-lg font-medium hover:text-gray-300 transition-all px-2 py-1 border border-transparent hover:border-gray-400 rounded"
                >
                  View / Edit Profile
                </button>
                <button
                  onClick={() => {
                    setIsOpen(false);
                    auth.logout();
                    navigate('/login');
                  }}
                  className="block text-left w-full text-lg font-medium hover:text-gray-300 transition-all px-2 py-1 border border-transparent hover:border-gray-400 rounded"
                >
                  Logout
                </button>
              </>
+           ) : (
+             <Link
+               to="/login"
+               className="block text-lg font-medium hover:text-gray-300 transition-all px-2 py-1 border border-transparent hover:border-gray-400 rounded"
+               onClick={() => setIsOpen(false)}
+             >
+               Login
+             </Link>
            )}
🧹 Nitpick comments (3)
src/context/AuthContext.tsx (3)

10-10: Improve type safety for getOctokit.

The return type any | null reduces type safety. Use Octokit | null for better type checking and IDE support.

Apply this diff:

 type AuthContextType = {
   username: string;
   token: string;
   setUsername: (u: string) => void;
   setToken: (t: string) => void;
   logout: () => void;
-  getOctokit: () => any | null;
+  getOctokit: () => Octokit | null;
 };

56-63: Consider memoizing Octokit instance for performance.

The getOctokit function creates a new Octokit instance on every call. If components call this frequently (e.g., in render or effects), it could impact performance.

Consider memoizing with useMemo:

+  const octokit = React.useMemo(() => {
+    if (!username || !token) return null;
+    try {
+      return new Octokit({ auth: token });
+    } catch (e) {
+      return null;
+    }
+  }, [username, token]);
+
   const getOctokit = () => {
-    if (!username || !token) return null;
-    try {
-      return new Octokit({ auth: token });
-    } catch (e) {
-      return null;
-    }
+    return octokit;
   };

19-45: Security: Personal Access Tokens stored in localStorage.

Storing GitHub PATs in localStorage exposes them to XSS attacks, as any JavaScript running on the page can access localStorage. While the PR description acknowledges this needs improvement for production, consider these alternatives:

  • httpOnly cookies: More secure against XSS (requires backend support)
  • sessionStorage: Cleared when tab closes (better than localStorage)
  • Memory-only storage: Most secure but lost on refresh

For production, implement secure token storage with backend session management or encrypted cookies.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 22e52f9 and 7ccb6ee.

📒 Files selected for processing (6)
  • src/Routes/Router.tsx (2 hunks)
  • src/components/Navbar.tsx (3 hunks)
  • src/context/AuthContext.tsx (1 hunks)
  • src/main.tsx (1 hunks)
  • src/pages/Profile/Profile.tsx (1 hunks)
  • src/pages/Tracker/Tracker.tsx (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/pages/Profile/Profile.tsx (1)
src/context/AuthContext.tsx (1)
  • AuthContext (13-13)
src/pages/Tracker/Tracker.tsx (1)
src/context/AuthContext.tsx (1)
  • AuthContext (13-13)
src/components/Navbar.tsx (2)
src/context/ThemeContext.tsx (1)
  • ThemeContext (10-10)
src/context/AuthContext.tsx (1)
  • AuthContext (13-13)
🪛 Biome (2.1.2)
src/pages/Profile/Profile.tsx

[error] 13-13: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 14-14: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

🔇 Additional comments (3)
src/Routes/Router.tsx (1)

9-9: LGTM!

The Profile route is properly imported and integrated consistently with the existing routing structure.

Also applies to: 22-22

src/main.tsx (1)

7-7: LGTM!

The AuthProvider is correctly positioned in the component tree. Components that consume AuthContext and use routing hooks (like Navbar and Profile) are rendered inside both the AuthProvider and BrowserRouter, ensuring they have access to both contexts.

Also applies to: 12-16

src/pages/Profile/Profile.tsx (1)

37-45: Verify: Token field is not required.

The Personal Access Token field lacks the required attribute (unlike the username field on line 33), allowing users to save an empty token. If this is intentional for clearing tokens, consider adding a confirmation or explicit "Clear Token" action for better UX.

Comment on lines +6 to +14
const auth = useContext(AuthContext);
const navigate = useNavigate();

if (!auth) return null;

const { username, token, setUsername, setToken } = auth;

const [localUsername, setLocalUsername] = useState(username || "");
const [localToken, setLocalToken] = useState(token || "");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Fix hook ordering to comply with Rules of Hooks.

The useState hooks on lines 13-14 are called after the early return on line 9, violating React's Rules of Hooks. Hooks must be called unconditionally in the same order on every render.

Apply this diff to fix the hook ordering:

 const Profile: React.FC = () => {
   const auth = useContext(AuthContext);
   const navigate = useNavigate();
+  const [localUsername, setLocalUsername] = useState("");
+  const [localToken, setLocalToken] = useState("");
 
   if (!auth) return null;
 
   const { username, token, setUsername, setToken } = auth;
-
-  const [localUsername, setLocalUsername] = useState(username || "");
-  const [localToken, setLocalToken] = useState(token || "");
+
+  // Sync with auth context values on mount/change
+  React.useEffect(() => {
+    setLocalUsername(username || "");
+    setLocalToken(token || "");
+  }, [username, token]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const auth = useContext(AuthContext);
const navigate = useNavigate();
if (!auth) return null;
const { username, token, setUsername, setToken } = auth;
const [localUsername, setLocalUsername] = useState(username || "");
const [localToken, setLocalToken] = useState(token || "");
const auth = useContext(AuthContext);
const navigate = useNavigate();
const [localUsername, setLocalUsername] = useState("");
const [localToken, setLocalToken] = useState("");
if (!auth) return null;
const { username, token, setUsername, setToken } = auth;
// Sync with auth context values on mount/change
React.useEffect(() => {
setLocalUsername(username || "");
setLocalToken(token || "");
}, [username, token]);
🧰 Tools
🪛 Biome (2.1.2)

[error] 13-13: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 14-14: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

🤖 Prompt for AI Agents
In src/pages/Profile/Profile.tsx around lines 6 to 14, the useState hooks are
called after an early return (if (!auth) return null), violating the Rules of
Hooks; move the hooks to execute unconditionally before any early returns: call
useContext(AuthContext), then declare the useState hooks (initializing with
auth?.username and auth?.token or empty strings) immediately, then perform the
guard/early-return based on auth (or render a loading/null) and finally
destructure setters from auth if needed; ensure hook order is preserved on every
render.

Comment on lines +53 to +60
const auth = useContext(AuthContext);

const username = auth?.username || "";
const setUsername = auth?.setUsername || (() => {});
const token = auth?.token || "";
const setToken = auth?.setToken || (() => {});
const authError = "";
const getOctokit = auth?.getOctokit || (() => null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Major issue: Authentication error handling removed.

The authError is hardcoded to an empty string (line 59), removing any authentication error feedback that may have been present in the previous useGitHubAuth hook implementation. Users won't see errors related to invalid credentials, API rate limits, or token issues.

Consider adding error state to AuthContext or handling authentication errors within the Tracker component:

  const auth = useContext(AuthContext);
  
  const username = auth?.username || "";
  const setUsername = auth?.setUsername || (() => {});
  const token = auth?.token || "";
  const setToken = auth?.setToken || (() => {});
- const authError = "";
+ const [authError, setAuthError] = useState("");
  const getOctokit = auth?.getOctokit || (() => null);

Then wrap the getOctokit call or data fetching with try-catch to set authError when authentication fails.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/pages/Tracker/Tracker.tsx around lines 53 to 60, authError is hardcoded
to an empty string which strips out authentication error handling; restore a
real error state by either reading authError from AuthContext (add it to the
context if missing) or creating a local state const [authError, setAuthError] =
useState<string>("") and remove the hardcoded value, then wrap getOctokit calls
and any GitHub API data fetching in try/catch blocks that call setAuthError with
the caught error message (and clear it on success); ensure any UI that showed
authentication errors uses this error state so users see credential/API/token
issues.

@nishanth-kj nishanth-kj changed the title feat(profile): add Profile page, AuthContext and navbar dropdown with logout Add app-wide AuthContext, Profile page, and navbar integration (Closes #47) Oct 26, 2025
@nishanth-kj nishanth-kj deleted the 47 branch October 26, 2025 15:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🚀 Feature: Add Profile page in frontend

1 participant